package com.zhny.aiot.four.solar.roll.film.plugin;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableMap;
import com.zhny.aiot.four.solar.roll.film.plugin.model.AdjustableParam;
import com.zhny.aiot.four.solar.roll.film.plugin.model.SolarRollFilm4GStoreEntry;
import com.zhny.aiot.plugin.ICenterFacilities;
import com.zhny.aiot.plugin.IDeviceFactory;
import com.zhny.aiot.plugin.core.model.IRequestMessage;
import com.zhny.aiot.plugin.core.utils.MessageUtils;
import com.zhny.aiot.plugin.modbus.ModemEngine;
import com.zhny.aiot.plugin.modbus.ModemServer;
import com.zhny.aiot.plugin.modbus.device.ModemConfig;
import com.zhny.aiot.plugin.modbus.device.ModemDevice;
import com.zhny.aiot.plugin.modbus.device.modbus.ModbusCommandParam;
import com.zhny.aiot.plugin.modbus.handler.model.ModemRequestMessage;
import com.zhny.aiot.plugin.modbus.handler.model.ModemResponseMessage;
import com.zhny.aiot.plugin.model.DeviceEntity;
import com.zhny.aiot.plugin.model.MessageEntry;
import com.zhny.aiot.plugin.model.MessageType;
import com.zhny.aiot.plugin.model.TaskEntity;
import io.netty.util.internal.StringUtil;
import org.pf4j.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;

public class SolarRollFilm4GDevice extends ModemDevice<SolarRollFilm4GStoreEntry> {
    private static final Logger logger=LoggerFactory.getLogger (SolarRollFilm4GDevice.class);
    private final Map<String, ModbusCommandParam> CommandOperations;

    public SolarRollFilm4GDevice(ModemEngine engine, IDeviceFactory<ModemConfig> factory, ICenterFacilities centerFacilities, DeviceEntity entity) {
        super (engine, factory, centerFacilities, entity);

        CommandOperations=new ImmutableMap.Builder<String, ModbusCommandParam> ()
                .put ("open", ModbusCommandParam.valueOf ((short) 6, 10, 0x0065))
                .put ("close", ModbusCommandParam.valueOf ((short) 6, 10, 0x0066))
                .put ("stop", ModbusCommandParam.valueOf ((short) 6, 10, 0x0068))
                .put ("value", ModbusCommandParam.valueOf ((short) 6, 10, 0x0064))
                .put ("query", ModbusCommandParam.valueOf ((short) 3, 2, 2))

                .build ();
    }

    @Override
    public void onDecoder(ModemResponseMessage modemResponseMessage) {
        MessageEntry entry=MessageUtils.createMessageEntry (this.getId ());
        entry.setType (MessageType.RESULT);
        entry.getProperties ().put ("gprs", ((ModemConfig) this.getConfig ()).getGprsNo ());
        entry.getProperties ().put ("address", ((ModemConfig) this.getConfig ()).getAddress ());

        int isRecord=modemResponseMessage.getData ().readByte ();
        int status=modemResponseMessage.getData ().readByte ();
        String value="";
        SolarRollFilm4GStoreEntry storeEntry=new SolarRollFilm4GStoreEntry ();
        if(modemResponseMessage.getFunction () == 0x06) {
            value=onStatusConvert (status);
        }else if(modemResponseMessage.getFunction () == 0x03) {
            int val = modemResponseMessage.getData ().readUnsignedShort ();
            value=onStatusConvert (status);
            double vald = createVol (val);
            storeEntry.setQuantity (findSOC(vald));
            logger.info ("4G卷膜器：{} ,电量值{}，电压值{}",
                    this.getDeviceEntity ().getName (),
                    storeEntry.getQuantity (),vald);
        }else {
            entry.setType (MessageType.ERROR);
            nofity (entry);
        }
        storeEntry.setStatus (value);
        logger.info ("4G卷膜器：{} 状态值:{}",
                this.getDeviceEntity ().getName (), value);
        entry.setData (storeEntry);
        nofity (entry);
        saveReal (storeEntry);
        save (storeEntry);
    }

    private String findSOC(double voltage) {
        // 定义电压和对应的SOC%
        double[] voltages = {8.766, 9.777, 10.389, 10.695, 10.926, 11.139, 11.469, 11.754, 12.033, 12.255, 12.525};
        String[] socs = {"0", "10", "20", "30", "40", "50", "60", "70", "80", "90", "100"};

        // 如果电压大于最大电压值，返回100%
        if (voltage >= voltages[voltages.length - 1]) {
            return socs[socs.length - 1];
        }

        // 如果电压小于最小电压值，返回0%
        if (voltage < voltages[0]) {
            return socs[0];
        }

//        y=4*x*x-58.4*x+204
//        for (int i = 0; i < voltages.length - 1; i++) {
//            if (voltage >= voltages[i] && voltage < voltages[i + 1]) {
//                return socs[i];
//            }
//        }
        return String.valueOf (calculateBatteryLevel(voltage));
    }
    private long calculateBatteryLevel(double voltage) {
        return Math.round (4 * voltage * voltage - 58.4 * voltage + 204);
    }
//    private String onQueryConvert(int status) {
//        return status == 0 ? "错误" :
//                status == 1 ? "全开" :
//                        status == 2 ? "全关" :
//                                status == 3 ? "半开":"异常";
//    }

    private String onStatusConvert(int status) {
        return status == 101 ? "全开" :
                status == 102 ? "全关" :
                        status == 103 ? "学习" :
                                status == 104 ? "停止" : String.valueOf (status);
    }
    private double createVol(int vol){
        double result = vol/100.00;
        return Double.parseDouble(String.format("%.2f",result));
    }
    @Override
    protected IRequestMessage getCommand(TaskEntity taskEntity) {
        MessageEntry entry=MessageUtils.createMessageEntry (this.getId ());
        entry.getProperties ().put ("task_name", taskEntity.getMethodName ());
        entry.setType (MessageType.OPERATION);
        ModbusCommandParam command=CommandOperations.get (taskEntity.getMethodName ());
        if(command == null) {
            logger.info (String.format ("factory[%s] no found func[%s]", getTypeId (), taskEntity.getMethodName ()));
            entry.setType (MessageType.ERROR);
            this.nofity (entry);
            return null;
        }
        logger.info ("quilt task func:{},param:{}",taskEntity.getMethodName (),taskEntity.getParams ());
        if(taskEntity.getMethodName ().equals ("value")){
           if(!StringUtils.isNullOrEmpty (taskEntity.getParams ())) {
               AdjustableParam param=null;
               ObjectMapper mapper = new ObjectMapper();
               mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
               try{
                   param = mapper.readValue (taskEntity.getParams (),AdjustableParam.class);
               }catch (Exception e){
                   logger.error ("Parse param error !");
                   return  null;
               }
               command = ModbusCommandParam.valueOf ((short)6,10, param.getValue ());
           }else if(taskEntity.getMethodName ().equals ("down")) {
               ModemServer.getInstance ().stop ();
           }else {
               logger.info (String.format ("factory[%s]  set adjust value command [%s] error param value:[%s]", getTypeId (), taskEntity.getMethodName (),taskEntity.getParams ()));
               entry.setType (MessageType.ERROR);
               this.nofity (entry);
               return null;
           }
        }

        return new ModemRequestMessage (
                Integer.valueOf (this.getConfig ().getAddress ()),
                command.getOper (),
                command.getRegAdress (),
                command.getDataSize ()
        );
    }

    @Override
    protected void disposable() {

    }
}
